﻿''' <summary>
''' Provides a single-line input window with command prompt. Updates an associated OutputWindow instance when parented to one.
''' </summary>
Public Class CommandLineWindow
    Inherits Window
    Public Event CommandEntered As EventHandler(Of CommandEnteredEventArgs)

    Public Property Prompt As String = ":> "
    Private userInput As New Text.StringBuilder
    Private history As New List(Of String)
    Private historyIndex As Integer

    Public Sub New()
        Bounds = New Rectangle(0, Console.WindowHeight - 3, Console.WindowWidth, 3)
        Content.Text = Prompt
    End Sub

    Protected Overrides Sub OnShown(e As EventArgs)
        MyBase.OnShown(e)
        If Parent IsNot Nothing Then Parent.Visible = True
        SetCursorLeft()
    End Sub

    Protected Overrides Sub OnHidden(e As EventArgs)
        MyBase.OnHidden(e)
        If Parent IsNot Nothing Then Parent.Visible = False
    End Sub

    Protected Overridable Sub OnCommandEntered(e As CommandEnteredEventArgs)
        history.Add(e.CommandLine)
        historyIndex = history.Count - 1
        RaiseEvent CommandEntered(Me, e)
    End Sub

    Protected Overrides Sub OnGotFocus(e As EventArgs)
        MyBase.OnGotFocus(e)
        SetCursorLeft()
    End Sub

    Protected Overrides Sub OnProcessKey(e As KeyProcessingEventArgs)
        MyBase.OnProcessKey(e)
        Select Case e.Key.Key
            Case ConsoleKey.Backspace
                If userInput.Length > 0 Then
                    Content.Text = Content.Text.Substring(0, Content.TextLength - 1)
                    userInput.Length -= 1
                    Console.CursorTop = textCursorTop
                    Console.CursorLeft = textCursorLeft - 2
                    firstLineVisible = Content.LineCount - 1
                End If
            Case ConsoleKey.Enter
                OnCommandEntered(New CommandEnteredEventArgs(userInput.ToString))
                userInput.Clear()
                Content.Text = Prompt
                firstLineVisible = 0
                SetCursorLeft()
            Case ConsoleKey.PageUp
                If Parent IsNot Nothing Then Parent.ScrollUp()
            Case ConsoleKey.PageDown
                If Parent IsNot Nothing Then Parent.ScrollDown()
            Case ConsoleKey.UpArrow
                If firstLineVisible = 0 Then
                    If history.Count > 0 Then
                        Content.Text = Prompt & history(historyIndex)
                        userInput.Clear()
                        userInput.Append(history(historyIndex))
                        Console.CursorLeft = Math.Min(Prompt.Length + userInput.Length + 1, Console.WindowWidth - 1)
                        historyIndex -= 1
                        If historyIndex < 0 Then historyIndex = history.Count - 1
                    End If
                End If
            Case Else
                Dim charNum As Integer = Asc(e.Key.KeyChar)
                If charNum > 31 AndAlso charNum < 128 Then
                    Content.Text &= e.Key.KeyChar
                    userInput.Append(e.Key.KeyChar)
                    Console.CursorTop = textCursorTop
                    If textCursorLeft > ClientBounds.Left + ClientBounds.Right Then textCursorLeft = ClientBounds.Left
                    Console.CursorLeft = textCursorLeft
                    If Not firstLineVisible = Content.LineCount - 1 Then firstLineVisible = Content.LineCount - 1 'firstLineVisible += 1
                End If
        End Select
    End Sub

    Protected Overrides Sub OnFirstVisibleLineChanged(e As EventArgs)
        MyBase.OnFirstVisibleLineChanged(e)
        SetCursorLeft()
    End Sub

    Public Overrides Sub ScrollDown()
        MyBase.ScrollDown()

    End Sub

    Public Overrides Sub ScrollUp()
        MyBase.ScrollUp()
    End Sub

    Protected Overrides Sub UpdateInternalBounds()
        MyBase.UpdateInternalBounds()
        _ClientBounds.Width -= 1
        Content._WindowClientBounds = _ClientBounds
    End Sub

    Private Sub SetCursorLeft()
        Dim bnds = ClientBounds
        OffsetByParents(bnds)
        Console.SetCursorPosition(bnds.Left + Content.Lines(firstLineVisible).LineLength, bnds.Top)
    End Sub

    Public Class CommandEnteredEventArgs
        Inherits EventArgs
        Public ReadOnly CommandLine As String
        Protected Friend Sub New(command As String)
            CommandLine = command
        End Sub
    End Class
End Class
